activatable: true,
singleLineMode: true,
text: ''});
- /* kind of a hack */
+ /* unmapping the edit box will un-focus it, undo that */
notebook.connect('selection', Lang.bind(this, function (nb, child) {
if (child == this._evalBox)
global.stage.set_key_focus(this._entry);
Tweener.removeTweens(this.actor);
- if (!Main.beginModal())
- return;
-
+ Main.pushModal(this.actor);
global.stage.set_key_focus(this._entry);
Tweener.addTween(this.actor, { time: 0.5,
this._open = false;
Tweener.removeTweens(this.actor);
- Main.endModal();
+ Main.popModal(this.actor);
Tweener.addTween(this.actor, { time: 0.5,
transition: "easeOutQuad",
let lookingGlass = null;
let wm = null;
let recorder = null;
-let inModal = false;
+let modalCount = 0;
+let modalActorFocusStack = [];
function start() {
// Add a binding for "global" in the global JS namespace; (gjs
// should be asking Mutter to resolve the key into an action and then
// base our handling based on the action.
function _globalKeyPressHandler(actor, event) {
- if (!inModal)
+ if (modalCount == 0)
return false;
let type = event.type();
return false;
}
-// Used to go into a mode where all keyboard and mouse input goes to
-// the stage. Returns true if we successfully grabbed the keyboard and
-// went modal, false otherwise
-function beginModal() {
+function _findModal(actor) {
+ for (let i = 0; i < modalActorFocusStack.length; i++) {
+ let [stackActor, stackFocus] = modalActorFocusStack[i];
+ if (stackActor == actor) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/**
+ * pushModal:
+ * @actor: #ClutterActor which will be given keyboard focus
+ *
+ * Ensure we are in a mode where all keyboard and mouse input goes to
+ * the stage. Multiple calls to this function act in a stacking fashion;
+ * the effect will be undone when an equal number of popModal() invocations
+ * have been made.
+ *
+ * Next, record the current Clutter keyboard focus on a stack. If the modal stack
+ * returns to this actor, reset the focus to the actor which was focused
+ * at the time pushModal() was invoked.
+ */
+function pushModal(actor) {
let timestamp = global.screen.get_display().get_current_time();
- if (!global.begin_modal(timestamp))
- return false;
- global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
+ modalCount += 1;
+ actor.connect('destroy', function() {
+ let index = _findModal(actor);
+ if (index >= 0)
+ modalActorFocusStack.splice(index, 1);
+ });
+ let curFocus = global.stage.get_key_focus();
+ if (curFocus != null) {
+ curFocus.connect('destroy', function() {
+ let index = _findModal(actor);
+ if (index >= 0)
+ modalActorFocusStack[index][1] = null;
+ });
+ }
+ modalActorFocusStack.push([actor, curFocus]);
- inModal = true;
+ if (modalCount > 1)
+ return;
- return true;
+ if (!global.begin_modal(timestamp)) {
+ log("pushModal: invocation of begin_modal failed");
+ return;
+ }
+ global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
}
-function endModal() {
+/**
+ * popModal:
+ * @actor: #ClutterActor passed to original invocation of pushModal().
+ *
+ * Reverse the effect of pushModal(). If this invocation is undoing
+ * the topmost invocation, then the focus will be restored to the
+ * previous focus at the time when pushModal() was invoked.
+ */
+function popModal(actor) {
let timestamp = global.screen.get_display().get_current_time();
+ modalCount -= 1;
+ let focusIndex = _findModal(actor);
+ if (focusIndex >= 0) {
+ if (focusIndex == modalActorFocusStack.length - 1) {
+ let [stackActor, stackFocus] = modalActorFocusStack[focusIndex];
+ global.stage.set_key_focus(stackFocus);
+ } else {
+ // Remove from the middle, shift the focus chain up
+ for (let i = focusIndex; i < modalActorFocusStack.length - 1; i++) {
+ modalActorFocusStack[i + 1][1] = modalActorFocusStack[i][1];
+ }
+ }
+ modalActorFocusStack.splice(focusIndex, 1);
+ }
+ if (modalCount > 0)
+ return;
+
global.end_modal(timestamp);
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
- inModal = false;
}
function createLookingGlass() {
this._internalCommands = { 'lg':
Lang.bind(this, function() {
- // Run in an idle to avoid recursive key grab problems
- Mainloop.idle_add(function() { Main.createLookingGlass().open(); });
+ Main.createLookingGlass().open();
}),
'r': Lang.bind(this, function() {
if (this._isOpen) // Already shown
return;
- if (!Main.beginModal())
- return;
-
this._isOpen = true;
this._group.show();
+ Main.pushModal(this._group);
global.stage.set_key_focus(this._entry);
},
this._group.hide();
this._entry.text = '';
- Main.endModal();
+ Main.popModal(this._group);
}
};
Signals.addSignalMethods(RunDialog.prototype);